package com.jahepi.android.modelo;

import java.util.ArrayList;
import java.util.Iterator;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;

import com.jahepi.android.Utils;
import com.jahepi.android.dto.Banco;
import com.jahepi.android.dto.Camion;
import com.jahepi.android.dto.Checador;
import com.jahepi.android.dto.Frente;
import com.jahepi.android.dto.Material;
import com.jahepi.android.dto.Obra;
import com.jahepi.android.dto.Presupuesto;
import com.jahepi.android.dto.Propietario;
import com.jahepi.android.dto.Tipo;
import com.jahepi.android.dto.Usuario;
import com.jahepi.android.dto.Viaje;

/* Data Access Object */

public class DAO {
	
	private final static String TAG = "DAO";
	private DB db;
	
	public DAO(Context context) {
		db = new DB(context);
		Log.d(TAG, "DAO inicializado");
	}
	
	public Usuario obtenerUsuario(String usuario, String clave) {
		Cursor cursor = db.obtener("usuarios", String.format("usuario='%s' AND clave = '%s' AND activo = 1", usuario, clave));
		if(cursor != null) {
			Usuario usuarioDto = new Usuario();
			usuarioDto.setUsuario(cursor.getString(0));
			usuarioDto.setClave(cursor.getString(1));
			usuarioDto.setNombre(cursor.getString(2));
			usuarioDto.setFechaModificacion(cursor.getString(3));
			usuarioDto.setActivo(cursor.getInt(4) != 0);
			usuarioDto.setPermisoFotografia(cursor.getInt(5) != 0);
			usuarioDto.setPermisoImpresion(cursor.getInt(6) != 0);
			cursor.close();
			
			ArrayList<Obra> obras = obtenerObrasPorUsuario(usuario);
			Iterator<Obra> iterator = obras.iterator();
			while(iterator.hasNext()) {
				usuarioDto.agregarObra(iterator.next());
			}
			
			return usuarioDto;
		}
		return null;
	}
	
	public Usuario obtenerUsuario(String usuario) {
		Cursor cursor = db.obtener("usuarios", String.format("usuario='%s'", usuario));
		if(cursor != null) {
			Usuario usuarioDto = new Usuario();
			usuarioDto.setUsuario(cursor.getString(0));
			usuarioDto.setClave(cursor.getString(1));
			usuarioDto.setNombre(cursor.getString(2));
			usuarioDto.setFechaModificacion(cursor.getString(3));
			usuarioDto.setActivo(cursor.getInt(4) != 0);
			usuarioDto.setPermisoFotografia(cursor.getInt(5) != 0);
			usuarioDto.setPermisoImpresion(cursor.getInt(6) != 0);
			cursor.close();
			
			ArrayList<Obra> obras = obtenerObrasPorUsuario(usuario);
			Iterator<Obra> iterator = obras.iterator();
			while(iterator.hasNext()) {
				usuarioDto.agregarObra(iterator.next());
			}
			
			return usuarioDto;
		}
		return null;
	}
	
	public ArrayList<Checador> obtenerChecadores(String usuario) {
		ArrayList<Checador> checadores = new ArrayList<Checador>();
		Cursor cursor = db.obtenerTodos("checadores", "usuario = '" + usuario + "' AND fecha_salida IS NULL AND fecha_entrada LIKE '%" + Utils.obtenerFechaActual() + "%'");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Checador checadorDto = new Checador();
				checadorDto.setId(cursor.getInt(0));
				checadorDto.setCamion(obtenerCamion(cursor.getInt(2), cursor.getString(1)));
				checadorDto.setUsuario(obtenerUsuario(cursor.getString(3)));
				checadorDto.setFechaEntrada(cursor.getString(4));
				checadorDto.setFechaSalida(cursor.getString(5) == null ? "" : cursor.getString(5));
				if(Checador.esValido(checadorDto)) {
					checadores.add(checadorDto);
				}
			}
			cursor.close();
		}
		return checadores;
	}
	
	public ArrayList<Checador> obtenerChecadoresNoSincronizados() {
		ArrayList<Checador> checadores = new ArrayList<Checador>();
		Cursor cursor = db.obtenerTodos("checadores", "sincronizado IS NULL OR sincronizado = 0");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Checador checadorDto = new Checador();
				checadorDto.setId(cursor.getInt(0));
				checadorDto.setCamion(obtenerCamion(cursor.getInt(2), cursor.getString(1)));
				checadorDto.setUsuario(obtenerUsuario(cursor.getString(3)));
				checadorDto.setFechaEntrada(cursor.getString(4));
				checadorDto.setFechaSalida(cursor.getString(5) == null ? "" : cursor.getString(5));
				if(Checador.esValido(checadorDto)) {
					checadores.add(checadorDto);
				}
			}
			cursor.close();
		}
		return checadores;
	}
	
	public Checador obtenerChecador(int id) {
		Cursor cursor = db.obtener("checadores", String.format("id='%s'", id));
		if(cursor != null) {
			Checador checadorDto = new Checador();
			checadorDto.setId(cursor.getInt(0));
			checadorDto.setCamion(obtenerCamion(cursor.getInt(2), cursor.getString(1)));
			checadorDto.setUsuario(obtenerUsuario(cursor.getString(3)));
			checadorDto.setFechaEntrada(cursor.getString(4));
			checadorDto.setFechaSalida(cursor.getString(5) == null ? "" : cursor.getString(5));
			cursor.close();
			return checadorDto;
		}
		return null;
	}
	
	public ArrayList<Tipo> obtenerTiposCamion() {
		ArrayList<Tipo> tipos = new ArrayList<Tipo>();
		Cursor cursor = db.obtenerTodos("tipos", "activo=1");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Tipo tipoDto = new Tipo(cursor.getInt(0), cursor.getString(1), cursor.getDouble(2));
				tipoDto.setFechaModificacion(cursor.getString(3));
				tipoDto.setActivo(cursor.getInt(4) != 0);
				tipos.add(tipoDto);
			}
			cursor.close();
		}
		return tipos;
	}
	
	public Tipo obtenerTipoCamion(int id) {
		Cursor cursor = db.obtener("tipos", String.format("id='%s'", id));
		if(cursor != null) {
			Tipo tipoDto = new Tipo(cursor.getInt(0), cursor.getString(1), cursor.getDouble(2));
			tipoDto.setFechaModificacion(cursor.getString(3));
			tipoDto.setActivo(cursor.getInt(4) != 0);
			cursor.close();
			return tipoDto;
		}
		return null;
	}
	
	public ArrayList<Obra> obtenerObras() {
		ArrayList<Obra> obras = new ArrayList<Obra>();
		Cursor cursor = db.obtenerTodos("obras", null);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Obra obraDto = new Obra(cursor.getString(0), cursor.getString(1));
				obraDto.setFechaModificacion(cursor.getString(2));
				obras.add(obraDto);
			}
			cursor.close();
		}
		return obras;
	}
	
	public Obra obtenerObra(String id) {
		Cursor cursor = db.obtener("obras", String.format("id='%s'", id));
		if(cursor != null) {
			Obra obraDto = new Obra(cursor.getString(0), cursor.getString(1));
			obraDto.setFechaModificacion(cursor.getString(2));
			cursor.close();
			return obraDto;
		}
		return null;
	}
	
	public ArrayList<Obra> obtenerObrasPorUsuario(String usuario) {
		ArrayList<Obra> obras = new ArrayList<Obra>();
		Cursor cursor = db.obtenerObrasPorUsuario(usuario);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Obra obraDto = new Obra(cursor.getString(0), cursor.getString(1));
				obraDto.setFechaModificacion(cursor.getString(2));
				obras.add(obraDto);
			}
			cursor.close();
		}
		return obras;
	}
	
	public ArrayList<Propietario> obtenerPropietarios(String obra) {
		ArrayList<Propietario> propietarios = new ArrayList<Propietario>();
		Cursor cursor = db.obtenerTodos("propietarios", String.format("obra='%s' AND activo=1", obra));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Propietario propietarioDto = new Propietario(cursor.getString(0), cursor.getString(2), obtenerObra(cursor.getString(1)));
				propietarioDto.setFechaModificacion(cursor.getString(3));
				propietarioDto.setActivo(cursor.getInt(4) != 0);
				propietarios.add(propietarioDto);
			}
			cursor.close();
		}
		return propietarios;
	}
	
	public Propietario obtenerPropietario(String id, String obra) {
		Cursor cursor = db.obtener("propietarios", String.format("id='%s' AND obra='%s'", id, obra));
		if(cursor != null) {
			Propietario propietarioDto = new Propietario(cursor.getString(0), cursor.getString(2), obtenerObra(cursor.getString(1)));
			propietarioDto.setFechaModificacion(cursor.getString(3));
			propietarioDto.setActivo(cursor.getInt(4) != 0);
			cursor.close();
			return propietarioDto;
		}
		return null;
	}
	
	public Camion obtenerCamion(int id, String obra) {
		Cursor cursor = db.obtener("camiones", String.format("id='%s' AND obra='%s'", id, obra));
		if(cursor != null) {
			Camion camionDto = new Camion();
			camionDto.setId(cursor.getInt(0));
			camionDto.setObra(obtenerObra(cursor.getString(1)));
			camionDto.setTipo(obtenerTipoCamion(cursor.getInt(2)));
			camionDto.setPropietario(obtenerPropietario(cursor.getString(3), cursor.getString(1)));
			camionDto.setAncho(cursor.getDouble(4));
			camionDto.setLargo(cursor.getDouble(5));
			camionDto.setAlto(cursor.getDouble(6));
			camionDto.setPlaca(cursor.getString(7));
			camionDto.setFotografia(cursor.getString(8));
			camionDto.setCapacidad(cursor.getDouble(9));
			cursor.close();
			return Camion.esValido(camionDto) ? camionDto : null;
		}
		return null;
	}
	
	public ArrayList<Camion> obtenerCamiones(String obra) {
		ArrayList<Camion> camiones = new ArrayList<Camion>();
		Cursor cursor = db.obtenerTodos("camiones", String.format("obra='%s'", obra));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Camion camionDto = new Camion();
				camionDto.setId(cursor.getInt(0));
				camionDto.setObra(obtenerObra(cursor.getString(1)));
				camionDto.setTipo(obtenerTipoCamion(cursor.getInt(2)));
				camionDto.setPropietario(obtenerPropietario(cursor.getString(3), cursor.getString(1)));
				camionDto.setAncho(cursor.getDouble(4));
				camionDto.setLargo(cursor.getDouble(5));
				camionDto.setAlto(cursor.getDouble(6));
				camionDto.setPlaca(cursor.getString(7));
				camionDto.setFotografia(cursor.getString(8));
				camionDto.setCapacidad(cursor.getDouble(9));
				if(Camion.esValido(camionDto)) {
					camiones.add(camionDto);
				}
			}
			cursor.close();
		}
		return camiones;
	}
	
	public ArrayList<Camion> obtenerCamionesNoSincronizados() {
		ArrayList<Camion> camiones = new ArrayList<Camion>();
		Cursor cursor = db.obtenerTodos("camiones", "sincronizado IS NULL OR sincronizado = 0");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Camion camionDto = new Camion();
				camionDto.setId(cursor.getInt(0));
				camionDto.setObra(obtenerObra(cursor.getString(1)));
				camionDto.setTipo(obtenerTipoCamion(cursor.getInt(2)));
				camionDto.setPropietario(obtenerPropietario(cursor.getString(3), cursor.getString(1)));
				camionDto.setAncho(cursor.getDouble(4));
				camionDto.setLargo(cursor.getDouble(5));
				camionDto.setAlto(cursor.getDouble(6));
				camionDto.setPlaca(cursor.getString(7));
				camionDto.setFotografia(cursor.getString(8));
				camionDto.setCapacidad(cursor.getDouble(9));
				if(Camion.esValido(camionDto)) {
					camiones.add(camionDto);
				}
			}
			cursor.close();
		}
		return camiones;
	}
	
	public Banco obtenerBanco(String id, String frente) {
		Cursor cursor = db.obtenerBanco(id, frente);
		if(cursor != null) {
			Banco bancoDto = new Banco();
			bancoDto.setId(cursor.getString(0));
			bancoDto.setFrente(obtenerFrente(cursor.getString(1), cursor.getString(6)));
			bancoDto.setNombre(cursor.getString(2));
			bancoDto.setDistancia(cursor.getDouble(3));
			bancoDto.setFechaModificacion(cursor.getString(4));
			bancoDto.setActivo(cursor.getInt(5) != 0);
			cursor.close();
			return bancoDto;
		}
		return null;
	}
	
	public ArrayList<Banco> obtenerBancos(String frente) {	
		ArrayList<Banco> bancos = new ArrayList<Banco>();
		Cursor cursor = db.obtenerBancos(frente);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Banco bancoDto = new Banco();
				bancoDto.setId(cursor.getString(0));
				bancoDto.setFrente(obtenerFrente(cursor.getString(1), cursor.getString(6)));
				bancoDto.setNombre(cursor.getString(2));
				bancoDto.setDistancia(cursor.getDouble(3));
				bancoDto.setFechaModificacion(cursor.getString(4));
				bancoDto.setActivo(cursor.getInt(5) != 0);
				bancos.add(bancoDto);
			}
			cursor.close();
		}
		return bancos;
	}
	
	public Frente obtenerFrente(String id, String obra) {
		Cursor cursor = db.obtener("frentes", String.format("id='%s' AND obra='%s'", id, obra));
		if(cursor != null) {
			Frente frenteDto = new Frente();
			frenteDto.setId(cursor.getString(0));
			frenteDto.setObra(obtenerObra(cursor.getString(1)));
			frenteDto.setNombre(cursor.getString(2));
			frenteDto.setFechaModificacion(cursor.getString(3));
			frenteDto.setActivo(cursor.getInt(4) != 0);
			cursor.close();
			return frenteDto;
		}
		return null;
	}
	
	public ArrayList<Frente> obtenerFrentes(String obra) {	
		ArrayList<Frente> frentes = new ArrayList<Frente>();
		Cursor cursor = db.obtenerTodos("frentes", String.format("obra='%s' AND activo=1", obra));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Frente frenteDto = new Frente();
				frenteDto.setId(cursor.getString(0));
				frenteDto.setObra(obtenerObra(cursor.getString(1)));
				frenteDto.setNombre(cursor.getString(2));
				frenteDto.setFechaModificacion(cursor.getString(3));
				frenteDto.setActivo(cursor.getInt(4) != 0);
				frentes.add(frenteDto);
			}
			cursor.close();
		}
		return frentes;
	}
	
	public Material obtenerMaterial(String id, String frente, String banco) {
		Cursor cursor = db.obtener("materiales", String.format("id='%s' AND banco='%s'", id, banco));
		if(cursor != null) {
			Material materialDto = new Material();
			materialDto.setId(cursor.getString(0));
			materialDto.setBanco(obtenerBanco(cursor.getString(1), frente));
			materialDto.setNombre(cursor.getString(2));
			materialDto.setUnidad(cursor.getString(3));
			materialDto.setCantidadFija((cursor.getInt(4) != 0));
			materialDto.setFechaModificacion(cursor.getString(5));
			materialDto.setActivo(cursor.getInt(6) != 0);
			materialDto.setCantidad(cursor.getDouble(7));
			cursor.close();
			return materialDto;
		}
		return null;
	}
	
	public ArrayList<Material> obtenerMateriales(String banco, String frente) {	
		ArrayList<Material> materiales = new ArrayList<Material>();
		Cursor cursor = db.obtenerTodos("materiales", String.format("banco='%s' AND activo=1", banco));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Material materialDto = new Material();
				materialDto.setId(cursor.getString(0));
				materialDto.setBanco(obtenerBanco(cursor.getString(1), frente));
				materialDto.setNombre(cursor.getString(2));
				materialDto.setUnidad(cursor.getString(3));
				materialDto.setCantidadFija((cursor.getInt(4) != 0));
				materialDto.setFechaModificacion(cursor.getString(5));
				materialDto.setActivo(cursor.getInt(6) != 0);
				materialDto.setCantidad(cursor.getDouble(7));
				materiales.add(materialDto);
			}
			cursor.close();
		}
		return materiales;
	}
	
	public Presupuesto obtenerPresupuesto(String obra, String material, String vigenciaDesde, String vigenciaHasta) {
		Cursor cursor = db.obtener("presupuestos", String.format("obra='%s' AND material='%s' AND vigencia_desde='%s' AND vigencia_hasta='%s'", obra, material, vigenciaDesde, vigenciaHasta));
		if(cursor != null) {
			Presupuesto presupuestoDto = new Presupuesto();
			presupuestoDto.setObra(cursor.getString(0));
			presupuestoDto.setMaterial(cursor.getString(1));
			presupuestoDto.setCantidad(cursor.getDouble(2));
			presupuestoDto.setVigenciaDesde(cursor.getString(3));
			presupuestoDto.setVigenciaHasta(cursor.getString(4));
			presupuestoDto.setFechaModificacion(cursor.getString(5));
			cursor.close();
			return presupuestoDto;
		}
		return null;
	}
	
	public Presupuesto obtenerPresupuesto(String obra, String material, String fecha) {
		Cursor cursor = db.obtener("presupuestos", "obra='" + obra + "' AND material='" + material + "' AND strftime('%s', '" + fecha + "') BETWEEN strftime('%s', vigencia_desde) AND strftime('%s', vigencia_hasta)");
		if(cursor != null) {
			Presupuesto presupuestoDto = new Presupuesto();
			presupuestoDto.setObra(cursor.getString(0));
			presupuestoDto.setMaterial(cursor.getString(1));
			presupuestoDto.setCantidad(cursor.getDouble(2));
			presupuestoDto.setVigenciaDesde(cursor.getString(3));
			presupuestoDto.setVigenciaHasta(cursor.getString(4));
			presupuestoDto.setFechaModificacion(cursor.getString(5));
			cursor.close();
			return presupuestoDto;
		}
		return null;
	}
	
	public int obtenerNumeroViajesPorPresupuesto(Presupuesto presupuesto) {
		Cursor cursor = db.obtenerNumeroViajes(presupuesto.getObra(), presupuesto.getMaterial(), presupuesto.getVigenciaDesde(), presupuesto.getVigenciaHasta());
		if(cursor != null) {
			cursor.moveToFirst();
			int n = cursor.getInt(0);
			cursor.close();
			return n;
		}
		return 0;
	}
	
	private Viaje viajeMapeador(Cursor cursor) {
		Viaje viajeDto = new Viaje();
		viajeDto.setId(cursor.getInt(0));
		viajeDto.setDispositivo(cursor.getString(1));
		viajeDto.setUsuario(obtenerUsuario(cursor.getString(2)));
		viajeDto.setFechaSalida(cursor.getString(3));
		viajeDto.setCamion(obtenerCamion(cursor.getInt(4), cursor.getString(9)));
		viajeDto.setFrente(obtenerFrente(cursor.getString(5), cursor.getString(9)));
		viajeDto.setBanco(obtenerBanco(cursor.getString(6), cursor.getString(5)));
		viajeDto.setMaterial(obtenerMaterial(cursor.getString(7), cursor.getString(5), cursor.getString(6)));
		viajeDto.setMaterialCantidad(cursor.getDouble(8));
		viajeDto.setLatitud(cursor.getDouble(10));
		viajeDto.setLongitud(cursor.getDouble(11));
		viajeDto.setFechaCancelacion(cursor.getString(14));
		viajeDto.setPendiente(cursor.getInt(15) == 1);
		viajeDto.setViajePendiente(cursor.getInt(16));
		viajeDto.setRemoteAndroidId(cursor.getInt(19));
		viajeDto.setFechaModificacion(cursor.getString(20));
		if(cursor.getString(18).equals(Viaje.TIPO_POR_VIAJE)) {
			viajeDto.setPorViaje();
		} else {
			viajeDto.setPorKm();
		}
		return viajeDto;
	}
	
	public Viaje obtenerViaje(int id) {
		Cursor cursor = db.obtener("viajes", String.format("id='%s'", id));
		if(cursor != null) {
			Viaje viajeDto = viajeMapeador(cursor);
			cursor.close();
			if(Viaje.esValido(viajeDto)) {
				return viajeDto;
			}
		}
		return null;
	}
	
	public ArrayList<Viaje> obtenerViajesNoSincronizados() {
		ArrayList<Viaje> viajes = new ArrayList<Viaje>();
		Cursor cursor = db.obtenerTodos("viajes", "sincronizado IS NULL");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Viaje viajeDto = viajeMapeador(cursor);
				if(Viaje.esValido(viajeDto)) {
					viajes.add(viajeDto);
				}
			}
			cursor.close();
		}
		return viajes;
	}
	
	public ArrayList<Viaje> obtenerViajesPendientes() {
		ArrayList<Viaje> viajes = new ArrayList<Viaje>();
		String where = "pendiente = 1 AND ocultar_pendiente IS NULL AND cancelado IS NULL AND strftime('%s', fecha) BETWEEN strftime('%s', '" + Utils.obtenerFecha(-6) + " 00:00:00') AND strftime('%s', '" + Utils.obtenerFechaActual() + " 23:59:59')";
		Cursor cursor = db.obtenerTodosOrdenadosPor("viajes", where, "id DESC");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Viaje viajeDto = viajeMapeador(cursor);
				if(Viaje.esValido(viajeDto)) {
					viajes.add(viajeDto);
				}
			}
			cursor.close();
		}
		return viajes;
	}
	
	public ArrayList<Viaje> obtenerViajesNoCanceladosDeHoy() {
		String where = "cancelado IS NULL AND pendiente = 0 AND strftime('%s', fecha) BETWEEN strftime('%s', '" + Utils.obtenerRangoFecha() + " 00:00:00') AND strftime('%s', '" + Utils.obtenerFechaActual() + " 23:59:59')";
		ArrayList<Viaje> viajes = new ArrayList<Viaje>();
		Cursor cursor = db.obtenerTodosOrdenadosPor("viajes", where, "id DESC");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Viaje viajeDto = viajeMapeador(cursor);
				if(Viaje.esValido(viajeDto)) {
					viajes.add(viajeDto);
				}
			}
			cursor.close();
		}
		return viajes;
	}
	
	public ArrayList<Viaje> obtenerViajesNoCanceladosDeHoy(int viaje, int camion) {
		String where = "cancelado IS NULL AND pendiente = 0 AND strftime('%s', fecha) BETWEEN strftime('%s', '" + Utils.obtenerRangoFecha() + " 00:00:00') AND strftime('%s', '" + Utils.obtenerFechaActual() + " 23:59:59')";
		if(viaje != 0) {
			where += String.format(" AND (id='%s' OR remote_android_id='%s')", viaje, viaje);
		}
		if(camion != 0) {
			where += String.format(" AND camion='%s'", camion);
		}
		ArrayList<Viaje> viajes = new ArrayList<Viaje>();
		Cursor cursor = db.obtenerTodosOrdenadosPor("viajes", where, "id DESC");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Viaje viajeDto = viajeMapeador(cursor);
				if(Viaje.esValido(viajeDto)) {
					viajes.add(viajeDto);
				}
			}
			cursor.close();
		}
		return viajes;
	}
	
	public ArrayList<Viaje> obtenerViajesCanceladosDeHoy() {
		ArrayList<Viaje> viajes = new ArrayList<Viaje>();
		Cursor cursor = db.obtenerTodos("viajes", "cancelado = 1 AND fecha LIKE '%" + Utils.obtenerFechaActual() + "%'");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Viaje viajeDto = viajeMapeador(cursor);
				if(Viaje.esValido(viajeDto)) {
					viajes.add(viajeDto);
				}
			}
			cursor.close();
		}
		return viajes;
	}
	
	public Viaje existeViaje(Viaje viaje) {
		String whereStr = "dispositivo='%s' AND usuario='%s' AND fecha='%s'";
		if(viaje.getPendiente()) {
			whereStr += " AND pendiente=1";
		}
		Cursor cursor = db.obtener("viajes", String.format(whereStr, viaje.getDispositivo(), viaje.getUsuarioId(), viaje.getFechaSalida()));
		if(cursor != null) {
			Viaje viajeDto = viajeMapeador(cursor);
			cursor.close();
			if(Viaje.esValido(viajeDto)) {
				return viajeDto;
			}
		}
		return null;
	}
	
	public boolean guardarUsuario(Usuario usuario) {
		if(usuario != null) {
			ContentValues values = new ContentValues();
			values.put("clave", usuario.getClave());
			values.put("nombre", usuario.getNombre());
			values.put("activo", usuario.estaActivo() ? 1 : 0);
			values.put("permiso_foto", usuario.tienePermisoFotografia() ? 1 : 0);
			values.put("permiso_impresion", usuario.tienePermisoImpresion() ? 1 : 0);
			values.put("fecha_modificacion", usuario.getFechaModificacionString());
			
			Usuario usuarioDB = obtenerUsuario(usuario.getUsuario());
			if(usuarioDB != null) {
				if(usuarioDB.esMayorFechaModificacion(usuario)) {
					db.actualizar("usuarios", values, String.format("usuario='%s'", usuario.getUsuario()));
				}
			} else {
				values.put("usuario", usuario.getUsuario());
				db.insertar("usuarios", values);
			}
					
			if(usuario.tieneObras()) {
				String[] obrasIds = new String[usuario.getCantidadObras()];
				int i = 0;
				Iterator<Obra> iterator = usuario.obtenerObrasIterator();
				while(iterator.hasNext()) {
					Obra obra = iterator.next();
					ContentValues values2 = new ContentValues();
					values2.put("usuario", usuario.getUsuario());
					values2.put("obra", obra.getId());
					obrasIds[i] = "'" + obra.getId() + "'";
					db.insertar("obras_usuarios", values2);
					i++;
				}
				db.borrarObrasUsuarioExcepto(obrasIds, usuario.getUsuario());
			} else {
				db.borrar("obras_usuarios", String.format("usuario='%s'", usuario.getUsuario()));
			}
			return true;
		}
		return false;
	}
	
	public boolean guardarObra(Obra obra) {
		if(obra != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", obra.getNombre());
			values.put("fecha_modificacion", obra.getFechaModificacionString());
			
			Obra obraDB = obtenerObra(obra.getId());
			if(obraDB != null) {
				if(obraDB.esMayorFechaModificacion(obra)) {
					return db.actualizar("obras", values, String.format("id='%s'", obra.getId()));
				}
			} else {
				values.put("id", obra.getId());
				return db.insertar("obras", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarTipo(Tipo tipo) {
		if(tipo != null) {
			ContentValues values = new ContentValues();
			values.put("tipo", tipo.getNombre());
			values.put("cubicaje", tipo.getCubicaje());
			values.put("fecha_modificacion", tipo.getFechaModificacionString());
			values.put("activo", tipo.estaActivo() ? 1 : 0);
			Tipo tipoDB = obtenerTipoCamion(tipo.getId());
			if(tipoDB != null) {
				if(tipoDB.esMayorFechaModificacion(tipo)) {
					return db.actualizar("tipos", values, String.format("id='%s'", tipo.getId()));
				}
			} else {
				values.put("id", tipo.getId());
				return db.insertar("tipos", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarPropietario(Propietario propietario) {
		if(propietario != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", propietario.getNombre());
			values.put("fecha_modificacion", propietario.getFechaModificacionString());
			values.put("activo", propietario.estaActivo() ? 1 : 0);
			Propietario propietarioDB = obtenerPropietario(propietario.getId(), propietario.getObraId());
			if(propietarioDB != null) {
				if(propietarioDB.esMayorFechaModificacion(propietario)) {
					return db.actualizar("propietarios", values, String.format("id='%s' AND obra='%s'", propietario.getId(), propietario.getObraId()));
				}
			} else {
				values.put("id", propietario.getId());
				values.put("obra", propietario.getObraId());
				return db.insertar("propietarios", values) != DB.ERROR;
			}
		}
		return false;
	}
	
	public boolean guardarBanco(Banco banco) {
		if(banco != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", banco.getNombre());
			values.put("distancia", banco.getDistancia());
			values.put("fecha_modificacion", banco.getFechaModificacionString());
			values.put("activo", banco.estaActivo() ? 1 : 0);
			Banco bancoDB = obtenerBanco(banco.getId(), banco.getFrenteId());
			if(bancoDB != null) {
				if(bancoDB.esMayorFechaModificacion(banco)) {
					return db.actualizar("bancos", values, String.format("id='%s' AND frente='%s'", banco.getId(), banco.getFrenteId()));
				}
			} else {
				values.put("id", banco.getId());
				values.put("frente", banco.getFrenteId());
				return db.insertar("bancos", values) != DB.ERROR;
			}
		}
		return false;
	}
	
	public boolean guardarFrente(Frente frente) {
		if(frente != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", frente.getNombre());
			values.put("fecha_modificacion", frente.getFechaModificacionString());
			values.put("activo", frente.estaActivo() ? 1 : 0);
			Frente frenteDB = obtenerFrente(frente.getId(), frente.getObraId());
			if(frenteDB != null) {
				if(frenteDB.esMayorFechaModificacion(frente)) {
					return db.actualizar("frentes", values, String.format("id='%s' AND obra='%s'", frente.getId(), frente.getObraId()));
				}
			} else {
				values.put("id", frente.getId());
				values.put("obra", frente.getObraId());
				return db.insertar("frentes", values) != DB.ERROR;
			}
		}
		return false;
	}
	
	public boolean guardarMaterial(Material material) {
		if(material != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", material.getNombre());
			values.put("unidad", material.getUnidad());
			values.put("fijo", material.esCantidadFija() ? 1 : 0);
			values.put("fecha_modificacion", material.getFechaModificacionString());
			values.put("activo", material.estaActivo() ? 1 : 0);
			values.put("cantidad", material.getCantidad());
			Material materialDB = obtenerMaterial(material.getId(), material.getFrenteId(), material.getBancoId());
			if(materialDB != null) {
				if(materialDB.esMayorFechaModificacion(material)) {
					return db.actualizar("materiales", values, String.format("id='%s' AND banco='%s'", material.getId(), material.getBancoId()));
				}
			} else {
				values.put("id", material.getId());
				values.put("banco", material.getBancoId());
				return db.insertar("materiales", values) != DB.ERROR;
			}
		}
		return false;
	}
	
	public boolean guardarPresupuesto(Presupuesto presupuesto) {
		if(presupuesto != null) {
			ContentValues values = new ContentValues();
			values.put("cantidad", presupuesto.getCantidad());
			values.put("fecha_modificacion", presupuesto.getFechaModificacionString());
			Presupuesto presupuestoDB = obtenerPresupuesto(presupuesto.getObra(), presupuesto.getMaterial(), presupuesto.getVigenciaDesde(), presupuesto.getVigenciaHasta());
			if(presupuestoDB != null) {
				if(presupuestoDB.esMayorFechaModificacion(presupuesto)) {
					return db.actualizar("presupuestos", values, String.format("obra='%s' AND material='%s' AND vigencia_desde='%s' AND vigencia_hasta='%s'", presupuesto.getObra(), presupuesto.getMaterial(), presupuesto.getVigenciaDesde(), presupuesto.getVigenciaHasta()));
				}
			} else {
				values.put("obra", presupuesto.getObra());
				values.put("material", presupuesto.getMaterial());
				values.put("vigencia_desde", presupuesto.getVigenciaDesde());
				values.put("vigencia_hasta", presupuesto.getVigenciaHasta());
				return db.insertar("presupuestos", values) != DB.ERROR;
			}
		}
		return false;
	}
	
	public boolean guardarCamion(Camion camion) {
		if(camion != null) {
			int id = Utils.obtenerID();
			Camion camionDto = obtenerCamion(id, camion.getObraId());
			
			while(camionDto != null) {
				id = Utils.obtenerID();
				camionDto = obtenerCamion(id, camion.getObraId());
			}
			
			camion.setId(id);
			
			ContentValues values = new ContentValues();
			values.put("id", camion.getId());
			values.put("obra", camion.getObraId());
			values.put("tipo", camion.getTipoId());
			values.put("propietario", camion.getPropietarioId());
			values.put("ancho", camion.getAncho());
			values.put("largo", camion.getLargo());
			values.put("alto", camion.getAlto());
			values.put("placa", camion.getPlaca());
			values.put("fotografia", camion.getFotografia());
			values.put("capacidad", camion.getCapacidad());		
			return db.insertar("camiones", values) != DB.ERROR;
		}
		return false;
	}
	
	public boolean guardarCamionComoSincronizado(Camion camion) {
		if(camion != null) {
			ContentValues values = new ContentValues();
			values.put("id", camion.getId());
			values.put("obra", camion.getObraId());
			values.put("tipo", camion.getTipoId());
			values.put("propietario", camion.getPropietarioId());
			values.put("ancho", camion.getAncho());
			values.put("largo", camion.getLargo());
			values.put("alto", camion.getAlto());
			values.put("placa", camion.getPlaca());
			values.put("fotografia", camion.getFotografia());
			values.put("capacidad", camion.getCapacidad());
			values.put("sincronizado", 1);
			return db.insertar("camiones", values) != DB.ERROR;
		}
		return false;
	}
	
	public boolean actualizarCamionComoSincronizado(Camion camion) {
		if(camion != null) {
			ContentValues values = new ContentValues();
			values.put("sincronizado", 1);
			return db.actualizar("camiones", values, "id=" + camion.getId() + " AND obra='" + camion.getObraId()+"'");
		}
		return false;
	}
	
	public boolean actualizarCamionFotografia(Camion camion) {
		if(camion != null) {
			ContentValues values = new ContentValues();
			values.put("fotografia", camion.getFotografia());
			values.put("sincronizado", 0);
			return db.actualizar("camiones", values, "id=" + camion.getId() + " AND obra='" + camion.getObraId()+"'");
		}
		return false;
	}
	
	public boolean guardarChecador(Checador checador) {
		if(checador != null) {
			ContentValues values = new ContentValues();
			values.put("obra", checador.getCamionObraId());
			values.put("camion", checador.getCamionId());
			values.put("usuario", checador.getUsuarioNombre());
			values.put("fecha_entrada", checador.getFechaEntrada());
			values.put("fecha_salida", checador.getFechaSalida());
			return db.insertar("checadores", values) != DB.ERROR;
		}
		return false;
	}
	
	public boolean actualizarChecador(Checador checador) {
		if(checador != null) {
			ContentValues values = new ContentValues();
			values.put("fecha_salida", checador.getFechaSalida());
			values.put("sincronizado", 0);
			return db.actualizar("checadores", values, "id=" + checador.getId());
		}
		return false;
	}
	
	public boolean actualizarChecadorComoSincronizado(Checador checador) {
		if(checador != null) {
			ContentValues values = new ContentValues();
			values.put("sincronizado", 1);
			return db.actualizar("checadores", values, "id=" + checador.getId());
		}
		return false;
	}
	
	public boolean guardarViaje(Viaje viaje, boolean sync) {
		if(viaje != null) {
			ContentValues values = new ContentValues();
			values.put("fecha", viaje.getFechaSalida());
			values.put("camion", viaje.getCamionId());
			values.put("frente", viaje.getFrenteId());
			values.put("usuario", viaje.getUsuarioId());
			values.put("dispositivo", viaje.getDispositivo());
			values.put("banco", viaje.getBancoId());
			values.put("material", viaje.getMaterialId());
			values.put("material_cantidad", viaje.getMaterialCantidad());
			values.put("obra", viaje.getObraId());
			values.put("latitud", viaje.getLatitud());
			values.put("longitud", viaje.getLongitud());
			values.put("pendiente", viaje.getPendiente() ? 1 : 0);
			values.put("viaje_pendiente", 0);
			values.put("tipo", viaje.getTipo());
			values.put("remote_android_id", viaje.getRemoteAndroidId());
			values.put("fecha_modificacion", viaje.getFechaModificacionString());
			if(sync) {
				values.put("sincronizado", 1);
			}
			long result = db.insertar("viajes", values);
			if(result != DB.ERROR) {
				viaje.setId((int)result);
				return true;
			}
		}
		return false;
	}
	
	public boolean guardarViajePendiente(Viaje viaje) {
		if(viaje != null) {
			ContentValues values = new ContentValues();
			values.put("fecha", viaje.getFechaSalida());
			values.put("camion", viaje.getCamionId());
			values.put("frente", viaje.getFrenteId());
			values.put("usuario", viaje.getUsuarioId());
			values.put("dispositivo", viaje.getDispositivo());
			values.put("banco", viaje.getBancoId());
			values.put("material", viaje.getMaterialId());
			values.put("material_cantidad", viaje.getMaterialCantidad());
			values.put("obra", viaje.getObraId());
			values.put("latitud", viaje.getLatitud());
			values.put("longitud", viaje.getLongitud());
			values.put("pendiente", 0);
			values.put("tipo", viaje.getTipo());
			values.put("fecha_modificacion", viaje.getFechaModificacionString());
			if(viaje.getRemoteAndroidId() == 0) {
				values.put("viaje_pendiente", viaje.getId());
			} else {
				values.put("viaje_pendiente", viaje.getRemoteAndroidId());
			}
			long result = db.insertar("viajes", values);
			if(result != DB.ERROR) {
				return ocultarViajePendiente(viaje);
			}
		}
		return false;
	}
	
	public boolean ocultarViajePendiente(Viaje viaje) {
		if(viaje != null) {
			ContentValues values = new ContentValues();
			values.put("ocultar_pendiente", 1);
			values.put("fecha_modificacion", viaje.getFechaModificacionString());
			return db.actualizar("viajes", values, "id=" + viaje.getId());
		}
		return false;
	}
	
	public boolean actualizarViajeComoSincronizado(Viaje viaje) {
		if(viaje != null) {
			ContentValues values = new ContentValues();
			values.put("sincronizado", 1);
			return db.actualizar("viajes", values, "id=" + viaje.getId());
		}
		return false;
	}
	
	public boolean actualizarViajeComoCancelado(Viaje viaje) {
		if(viaje != null) {
			ContentValues values = new ContentValues();
			values.put("cancelado", 1);
			values.put("fecha_cancelacion", viaje.getFechaCancelacion());
			values.put("fecha_modificacion", viaje.getFechaModificacionString());
			return db.actualizar("viajes", values, "id=" + viaje.getId());
		}
		return false;
	}
	
	public void borrarPropietariosExcepto(ArrayList<Propietario> propietarios) {
		int size = propietarios.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Propietario> iterator = propietarios.iterator();
			while(iterator.hasNext()) {
				Propietario propietario = iterator.next();
				condiciones[i] = String.format("(id='%s' AND obra='%s')", propietario.getId(), propietario.getObraId()); i++;
			}
			db.borrar("propietarios", "NOT (" + Utils.implode(condiciones, " OR ") + ")");
		} else {
			db.borrar("propietarios", null);
		}
	}
	
	public void borrarFrentesExcepto(ArrayList<Frente> frentes) {
		int size = frentes.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Frente> iterator = frentes.iterator();
			while(iterator.hasNext()) {
				Frente frente = iterator.next();
				condiciones[i] = String.format("(id='%s' AND obra='%s')", frente.getId(), frente.getObraId()); i++;
			}
			db.borrar("frentes", "NOT (" + Utils.implode(condiciones, " OR ") + ")");
		} else {
			db.borrar("frentes", null);
		}
	}

	public void borrarBancosExcepto(ArrayList<Banco> bancos) {
		int size = bancos.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Banco> iterator = bancos.iterator();
			while(iterator.hasNext()) {
				Banco banco = iterator.next();
				condiciones[i] = String.format("(id='%s' AND frente='%s')", banco.getId(), banco.getFrenteId()); i++;
			}
			db.borrar("bancos", "NOT (" + Utils.implode(condiciones, " OR ") + ")");
		} else {
			db.borrar("bancos", null);
		}
	}

	public void borrarMaterialesExcepto(ArrayList<Material> materiales) {
		int size = materiales.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Material> iterator = materiales.iterator();
			while(iterator.hasNext()) {
				Material material = iterator.next();
				condiciones[i] = String.format("(id='%s' AND banco='%s')", material.getId(), material.getBancoId()); i++;
			}
			db.borrar("materiales", "NOT (" + Utils.implode(condiciones, " OR ") + ")");
		} else {
			db.borrar("materiales", null);
		}
	}
	
	public void borrarPresupuestosExcepto(ArrayList<Presupuesto> presupuestos) {
		int size = presupuestos.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Presupuesto> iterator = presupuestos.iterator();
			while(iterator.hasNext()) {
				Presupuesto presupuesto = iterator.next();
				condiciones[i] = String.format("(obra='%s' AND material='%s' AND vigencia_desde='%s' AND vigencia_hasta='%s')", presupuesto.getObra(), presupuesto.getMaterial(), presupuesto.getVigenciaDesde(), presupuesto.getVigenciaHasta()); i++;
			}
			db.borrar("presupuestos", "NOT (" + Utils.implode(condiciones, " OR ") + ")");
		} else {
			db.borrar("presupuestos", null);
		}
	}
}
